package net.pimpas.web.tomcat.serviceprovider.configuration;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import net.pimpas.core.configuration.Configuration;
import net.pimpas.core.configuration.exception.ConfigurationException;
import net.pimpas.core.configuration.file.FileConfiguration;
import net.pimpas.logging.serviceprovider.LoggingServiceProvider;
import net.pimpas.logging.serviceprovider.LoggingServiceProviderFactoryImpl;
import net.pimpas.xml.exception.XmlAccessException;
import net.pimpas.xml.exception.XmlParseException;
import net.pimpas.xml.node.Node;
import net.pimpas.xml.serviceprovider.XmlServiceProvider;
import net.pimpas.xml.serviceprovider.XmlServiceProviderFactoryImpl;

import org.apache.catalina.Context;
import org.apache.catalina.Engine;
import org.apache.catalina.Host;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.startup.Embedded;
import org.apache.commons.modeler.util.IntrospectionUtils;

public class TomcatServiceProviderConfiguration implements Configuration<FileConfiguration> {

	private List<FileConfiguration> filesConfiguration;
	private Embedded embedd;
	private LoggingServiceProvider logger = LoggingServiceProviderFactoryImpl.getLoggingServiceProvider(TomcatServiceProviderConfiguration.class);
	private static final String DEFAULT_TOMCAT_PATH			= System.getProperty("user.dir")+"\\target\\tomcat";
	private static final String DEFAULT_TOMCAT_WEB_PATH		= System.getProperty("user.dir")+"\\src\\main\\webapp";
	private static final String DEFAULT_TOMCAT_WORK_DIR 	= DEFAULT_TOMCAT_PATH+"\\work";
	private static final Integer DEFAULT_RUNNING_PORT		= 8080;
	private static final Integer DEFAULT_REMOTE_DEBUG_PORT	= 8081;
	
	public TomcatServiceProviderConfiguration() {
		this.setFilesConfiguration(new ArrayList<FileConfiguration>());
	}
	
	public void consume() throws ConfigurationException {
		FileConfiguration fc = this.getFilesConfiguration().get(0);
		XmlServiceProvider xmlReader = XmlServiceProviderFactoryImpl.getXmlServiceProvider();
		try {
			xmlReader.parse(fc.getInputStream());
			// get properties
			List<Node> properties = xmlReader.getChildrens("property");
			Node node = null;
			Integer portR, portD;
			portR = portD = null;
			String tomcatPath = null;
			String tomcatWorkDir = null;
			boolean sslEnabled = false;
			String keyStoreFile = null;
			String keyStorePassword = null;
			String keyStoreType = null;
			String sslProtocol = null;
			String sslClientAuth = null;			
			for(int i=0;i<properties.size();i++) {
				node = properties.get(i);
				if(xmlReader.getAttribute(node, "name").getText().equals("tomcat.http.port") &&
						!node.getText().equals(""))
					portR = Integer.parseInt(node.getText());
				else if(xmlReader.getAttribute(node, "name").getText().equals("tomcat.http.remote.debug.port") &&
						!node.getText().equals(""))
					portD = Integer.parseInt(node.getText());
				else if(xmlReader.getAttribute(node, "name").getText().equals("tomcat.local.path") &&
						!node.getText().equals(""))
					tomcatPath = node.getText();
				else if(xmlReader.getAttribute(node, "name").getText().equals("tomcat.work.path") &&
						!node.getText().equals(""))
					tomcatWorkDir = node.getText();
				else if(xmlReader.getAttribute(node, "name").getText().equals("tomcat.ssl.enabled"))
					sslEnabled = Boolean.valueOf(node.getText());
				else if(xmlReader.getAttribute(node, "name").getText().equals("tomcat.ssl.protocol"))
					sslProtocol = node.getText();
				else if(xmlReader.getAttribute(node, "name").getText().equals("tomcat.keystoreFile"))
					keyStoreFile = System.getProperty("user.dir")+"\\"+node.getText();
				else if(xmlReader.getAttribute(node, "name").getText().equals("tomcat.keystorePass"))
					keyStorePassword = node.getText();
				else if(xmlReader.getAttribute(node, "name").getText().equals("tomcat.keystoreType"))
					keyStoreType = node.getText();
				else if(xmlReader.getAttribute(node, "name").getText().equals("tomcat.ssl.clientAuth"))
					sslClientAuth = node.getText();
				
			}
			
			if(tomcatPath == null) 		tomcatPath = DEFAULT_TOMCAT_PATH;
			if(tomcatWorkDir == null) 	tomcatWorkDir = DEFAULT_TOMCAT_WORK_DIR;	
			if(portR == null) 			portR = DEFAULT_RUNNING_PORT;
			if(portD == null) 			portD = DEFAULT_REMOTE_DEBUG_PORT;
			
			logger.debug("[TOMCATSERVICEPROVIDER]: TomcatPath: ["+tomcatPath+"], TomcatWorkDir: ["+tomcatWorkDir+"]");
			
			Engine engine = embedd.createEngine();
			Host host = embedd.createHost("localhost", tomcatPath);
			// check standarHost
			if(host instanceof StandardHost) {
				StandardHost shost = (StandardHost) host;
				shost.setWorkDir(tomcatWorkDir);
				shost.setLiveDeploy(true);
				shost.setAutoDeploy(true);
			}
			
			// add host
			engine.addChild(host);
			engine.setDefaultHost(host.getName());
			this.getEmbedd().addEngine(engine);
			
			// process hosts
			List<Node> paths = xmlReader.getChildrens("path");
			int i;
			for(i=0;i<paths.size();i++)
				this.addServerContext(xmlReader.getAttribute(paths.get(i), "serverPath").getText(),
						xmlReader.getAttribute(paths.get(i), "localPath").getText(), host, embedd);
			if(i == 0)
				// create default path
				this.addServerContext("/",
						DEFAULT_TOMCAT_WEB_PATH, host, embedd);
			// create connector
			Connector connector = embedd.createConnector((String)null, portR, false);
			// process SSL
			if(sslEnabled) {
				logger.debug("[TOMCATSERVIDEPROVIDER]: Enabling SSL Support for Tomcat");
				IntrospectionUtils.setProperty(connector, "sslProtocol",
				   sslProtocol);
				IntrospectionUtils.setProperty(connector, "keystoreFile", 
						   keyStoreFile);
				IntrospectionUtils.setProperty(connector, "keystorePass", 
						   keyStorePassword);
				IntrospectionUtils.setProperty(connector, "keystoreType",
				   keyStoreType);
				IntrospectionUtils.setProperty(connector, "clientAuth", 
				   sslClientAuth);
				IntrospectionUtils.setProperty(connector, "scheme", 
						   "https");
				IntrospectionUtils.setProperty(connector, "secure", 
				   "true");
				connector.setProtocol( "SSL" );
			}
			embedd.addConnector(connector);
			embedd.start();
		} catch (XmlParseException e) {
			logger.error(e);
			throw new ConfigurationException(e);
		} catch (XmlAccessException e) {
			logger.error(e);
			throw new ConfigurationException(e);
		} catch (LifecycleException e) {
			logger.error(e);
			throw new ConfigurationException(e);
		}
	}
	
	private void addServerContext( String path, String localPath, Host host, Embedded embedd ) {
		File f = new File(localPath); 
		if(f.exists()){
			logger.debug("[TomcatServer EMBEDD]: Adding Path ["+localPath+"] as context ["+path+"] ");
			Context ctx = embedd.createContext(path,localPath);
			ctx.setReloadable(true);			
			((StandardContext)ctx).setCachingAllowed(false);			
			host.addChild(ctx);
		}
	}

	public List<FileConfiguration> getFilesConfiguration() {
		return this.filesConfiguration;
	}

	public String getName() {
		return this.getClass().getSimpleName();
	}

	public void setFilesConfiguration(List<FileConfiguration> filesConfiguration) {
		this.filesConfiguration = filesConfiguration;
	}

	public Embedded getEmbedd() {
		return embedd;
	}

	public void setEmbedd(Embedded embedd) {
		this.embedd = embedd;
	}

	public List<FileConfiguration> getConfigurationSources() {
		return this.getFilesConfiguration();
	}
}